package com.ddpt.platform.common.enums;

import cn.hutool.core.util.HexUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.asymmetric.*;
import cn.hutool.crypto.symmetric.AES;
import com.ddpt.platform.common.beans.SecretBean;
import com.ddpt.platform.common.util.AssertUtil;
import org.apache.commons.lang3.StringUtils;

import java.nio.charset.StandardCharsets;
import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Base64;
import java.util.Optional;
import java.util.stream.Stream;

/**
 * 加密类型和方式
 */
public enum SecretTypeEnum {

    AES_default("AES"){

        @Override
        public SecretBean generate(String encryptAlgorithm,String signAlgorithm) {
            SecretBean bean = new SecretBean();
            bean.setSecretType(SecretTypeEnum.AES_default);
            bean.setSecretKey(RandomUtil.randomString(16));
            return bean;
        }

        @Override
        public String encrypt(String text, SecretBean bean) {
            String secretKey = bean.getSecretKey();
            AssertUtil.isEmpty(secretKey,"密钥为空");
            return new AES(secretKey.getBytes()).encryptBase64(text);
        }

        @Override
        public String decrypt(String text, SecretBean bean) {
            String secretKey = bean.getSecretKey();
            AssertUtil.isEmpty(secretKey,"密钥为空");
            return new AES(secretKey.getBytes()).decryptStr(text);
        }

        @Override
        public String toSign(String text, SecretBean bean) {
            return encrypt(text,bean);
        }

        @Override
        public boolean verifySign(String text,String sign, SecretBean bean) {
            return encrypt(text,bean).equals(sign);
        }
    },
    SM2_default("SM2"){
        @Override
        public SecretBean generate(String encryptAlgorithm,String signAlgorithm) {
            SecretBean bean = new SecretBean();
            //随机生成秘钥
            SM2 sm2 = new SM2();
            //获取秘钥对象
            PrivateKey privateKeyObject = sm2.getPrivateKey();
            PublicKey publicKeyObject = sm2.getPublicKey();
            //生成私钥
            String privateKeyBase64 = Base64.getEncoder().encodeToString(privateKeyObject.getEncoded());
            //生成公钥
            String publicKeyBase64 = Base64.getEncoder().encodeToString(publicKeyObject.getEncoded());
            bean.setSecretType(SecretTypeEnum.SM2_default);
            bean.setPublicKey(publicKeyBase64);
            bean.setPrivateKey(privateKeyBase64);
            return bean;
        }

        @Override
        public String encrypt(String text, SecretBean bean) {
            //使用对方公钥加密
            String publicKey = bean.getPlatformPublicKey();
            String privateKey = bean.getPrivateKey();
            String encryptAlgorithm = bean.getEncryptAlgorithm();
            //创建sm2 对象
            SM2 sm2 = null;
            if(StringUtils.isNotBlank(encryptAlgorithm)){
                sm2 = new SM2(privateKey,publicKey,encryptAlgorithm);
            }else{
                sm2 = new SM2(privateKey,publicKey);
            }
            if(bean.getEncryptKeyType() == KeyTypeEnum.Public){
                // 公钥加密
                return sm2.encryptBcd(text, KeyType.PublicKey);
            }
            return sm2.encryptBcd(text, KeyType.PrivateKey);
        }

        @Override
        public String decrypt(String text, SecretBean bean) {
            //使用自身私钥解密
            String privateKey = bean.getPrivateKey();
            String publicKey = bean.getPlatformPublicKey();
            String encryptAlgorithm = bean.getEncryptAlgorithm();
            //创建sm2 对象
            SM2 sm2 = null;
            if(StringUtils.isNotBlank(encryptAlgorithm)){
                sm2 = new SM2(privateKey,publicKey,encryptAlgorithm);
            }else{
                sm2 = new SM2(privateKey,publicKey);
            }
            if(bean.getEncryptKeyType() == KeyTypeEnum.Public){
                // 如果是公钥加密，那就私钥解密
                return StrUtil.utf8Str(sm2.decryptFromBcd(text, KeyType.PrivateKey));
            }
            return StrUtil.utf8Str(sm2.decryptFromBcd(text, KeyType.PublicKey));
        }

        @Override
        public String toSign(String text, SecretBean bean) {
            //使用自身私钥签名
            String privateKey = bean.getPrivateKey();
            //创建sm2 对象
            SM2 sm2 = new SM2(privateKey, null);
            return sm2.signHex(HexUtil.encodeHexStr(text),bean.getSignAlgorithm());
        }

        @Override
        public boolean verifySign(String text,String sign, SecretBean bean) {
            //使用对方公钥验签
            String publicKey = bean.getPlatformPublicKey();
            //创建sm2 对象
            SM2 sm2 = new SM2(null, publicKey);
            return sm2.verifyHex(HexUtil.encodeHexStr(text), sign,bean.getSignAlgorithm());
        }
    },
    RSA_default("RSA"){
        @Override
        public SecretBean generate(String encryptAlgorithm,String signAlgorithm) {
            SecretBean bean = new SecretBean();
            if(StringUtils.isBlank(encryptAlgorithm)){
                encryptAlgorithm = "RSA/ECB/PKCS1Padding";
            }
            KeyPair pair = SecureUtil.generateKeyPair(encryptAlgorithm);
            PrivateKey privateKey = pair.getPrivate();
            PublicKey publicKey = pair.getPublic();
            // 获取 公钥和私钥 的 编码格式（通过该 编码格式 可以反过来 生成公钥和私钥对象）
            byte[] pubEncBytes = publicKey.getEncoded();
            byte[] priEncBytes = privateKey.getEncoded();

            // 把 公钥和私钥 的 编码格式 转换为 Base64文本 方便保存
            String pubEncBase64 = Base64.getEncoder().encodeToString(pubEncBytes);
            String priEncBase64 = Base64.getEncoder().encodeToString(priEncBytes);
            bean.setPrivateKey(priEncBase64);
            bean.setPublicKey(pubEncBase64);
            bean.setEncryptAlgorithm(encryptAlgorithm);
            if(StringUtils.isBlank(signAlgorithm)){
                signAlgorithm = "SHA1withRSA";
            }
            bean.setSignAlgorithm(signAlgorithm);
            Optional<SignAlgorithm> first = Stream.of(SignAlgorithm.values()).filter(item -> item.getValue().equalsIgnoreCase(bean.getSignAlgorithm())).findFirst();
            AssertUtil.isTrue(!first.isPresent(),"签名算法不存在");
            bean.setSecretType(SecretTypeEnum.RSA_default);
            return bean;
        }

        @Override
        public String encrypt(String text, SecretBean bean) {
            String privateKey = bean.getPrivateKey();
            String publicKey = bean.getPlatformPublicKey();
            String encryptAlgorithm = "RSA/ECB/PKCS1Padding";
            if(StringUtils.isNotBlank(bean.getEncryptAlgorithm())){
                encryptAlgorithm = bean.getEncryptAlgorithm();
            }
            RSA rsa = new RSA(encryptAlgorithm,privateKey,publicKey);
            if(bean.getEncryptKeyType() == KeyTypeEnum.Public){
                return rsa.encryptBase64(text.getBytes(),KeyType.PublicKey);
            }
            return rsa.encryptBase64(text.getBytes(),KeyType.PrivateKey);
        }

        @Override
        public String decrypt(String text, SecretBean bean) {
            String privateKey = bean.getPrivateKey();
            String publicKey = bean.getPlatformPublicKey();
            String encryptAlgorithm = "RSA/ECB/PKCS1Padding";
            if(StringUtils.isNotBlank(bean.getEncryptAlgorithm())){
                encryptAlgorithm = bean.getEncryptAlgorithm();
            }
            RSA rsa = new RSA(encryptAlgorithm,privateKey,publicKey);
            if(bean.getEncryptKeyType() == KeyTypeEnum.Public){
                return rsa.decryptStr(text,KeyType.PrivateKey);
            }
            return rsa.decryptStr(text,KeyType.PublicKey);
        }

        @Override
        public String toSign(String text, SecretBean bean) {
            String privateKey = bean.getPrivateKey();
            SignAlgorithm signAlgorithm = SignAlgorithm.SHA1withRSA;
            if(StringUtils.isNotBlank(bean.getSignAlgorithm())){
                Optional<SignAlgorithm> first = Stream.of(SignAlgorithm.values()).filter(item -> item.getValue().equalsIgnoreCase(bean.getSignAlgorithm())).findFirst();
                AssertUtil.isTrue(!first.isPresent(),"签名算法不存在");
                signAlgorithm = first.get();
            }
            Sign sign = new Sign(signAlgorithm,privateKey,null);
            return Base64.getEncoder().encodeToString(sign.sign(text.getBytes(StandardCharsets.UTF_8)));
        }

        @Override
        public boolean verifySign(String text, String sign, SecretBean bean) {
            SignAlgorithm signAlgorithm = SignAlgorithm.SHA1withRSA;
            if(StringUtils.isNotBlank(bean.getSignAlgorithm())){
                Optional<SignAlgorithm> first = Stream.of(SignAlgorithm.values()).filter(item -> item.getValue().equalsIgnoreCase(bean.getSignAlgorithm())).findFirst();
                AssertUtil.isTrue(!first.isPresent(),"签名算法不存在");
                signAlgorithm = first.get();
            }
            Sign s = new Sign(signAlgorithm, null, bean.getPlatformPublicKey());
            return s.verify(text.getBytes(StandardCharsets.UTF_8), Base64.getDecoder().decode(sign.getBytes(StandardCharsets.UTF_8)));
        }
    }
    ;

    public String title;

    SecretTypeEnum(String title) {
        this.title = title;
    }

    /**
     * 生成密钥
     */
    public abstract SecretBean generate(String encryptAlgorithm,String signAlgorithm);

    /**
     * 数据加密
     * @param text 明文
     * @param bean    配置信息
     * @return  密文
     */
    public abstract String encrypt(String text, SecretBean bean);

    /**
     * 数据解密
     * @param text  密文
     * @param bean    配置信息
     * @return  明文
     */
    public abstract String decrypt(String text,SecretBean bean);

    /**
     * 数据加签
     * @param text  原文
     * @param bean    配置信息
     * @return  签名
     */
    public abstract String toSign(String text,SecretBean bean);

    /**
     * 数据验签
     * @param text  签名
     * @param bean    配置信息
     * @return  是否通过验签
     */
    public abstract boolean verifySign(String text,String sign,SecretBean bean);

    public static void main(String[] args) {
        SecretTypeEnum secret = SecretTypeEnum.RSA_default;
        SecretBean bean = secret.generate(null,null);
        bean.setPlatformPublicKey(bean.getPublicKey());
        String text = "hahahah";
        String encrypt = secret.encrypt(text, bean);
        System.out.println(encrypt);
        String decrypt = secret.decrypt(encrypt, bean);
        System.out.println(decrypt);
        String sign = secret.toSign(text, bean);
        System.out.println(sign);
        System.out.println(secret.verifySign(text,sign,bean));
    }
}
